#pragma once

#include <string>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>
#include "Thread.hpp"
#include "Log.hpp"
#include "LockGuard.hpp"

using namespace std;

const int default_threadnum = 3;

class ThreadDate
{
public:
    ThreadDate(const string &name)
        : threadname(name)
    {
    }
    ~ThreadDate()
    {
    }

public:
    string threadname;
};

template <class T>
class ThreadPool
{
public:
    static ThreadPool *GetInstance()
    {
        if (_psl == nullptr)
        {
            LockGuard lock(&_sig_lock);
            if (_psl == nullptr)
            {
                lg.LogMessage(Info, "create singleton is success\n");
                _psl = new ThreadPool<T>();
            }
        }
        return _psl;
    }

    static void DelInstance()
	{
		if (_psl)
		{
			LockGuard lock(&_sig_lock);
			if (_psl)
			{
				delete _psl;
				_psl = nullptr;
                
                lg.LogMessage(Info, "destroy singleton is success\n");
			}
		}
	}

    // 启动所有线程
    bool Start()
    {
        for (auto &t : _threads)
        {
            t.Start();
            lg.LogMessage(Info, "%s , is running...\n", t.ThreadName().c_str());
        }

        return true;
    }

    // 等待所有线程终止
    void Join()
    {
        for (auto &t : _threads)
        {
            t.Join();
        }
    }

    // 线程等待当前条件变量
    void Thread_Wait(const ThreadDate &td)
    {
        pthread_cond_wait(&_cond, &_mutex);
        lg.LogMessage(Debug, "no task , %s is sleeping...\n", td.threadname.c_str());
    }

    // 唤醒当前条件变量下的某个线程
    void Thread_Wakeup()
    {
        pthread_cond_signal(&_cond);
    }

    // 添加任务
    bool Push(T &in)
    {
        LockGuard lockguard(&_mutex);
        _q.push(in);
        Thread_Wakeup();

        return true;
    }

    // 线程需要执行的回调函数
    void ThreadRun(const ThreadDate &td)
    {
        while (1)
        {
            T t;

            // 取任务
            {
                LockGuard lockguard(&_mutex);

                while (_q.empty())
                {
                    Thread_Wait(td);
                    lg.LogMessage(Debug, "haven task , %s is wakeup\n", td.threadname.c_str());
                }
                t = _q.front();
                _q.pop();
            }
            // 执行任务
            t();
            // lg.LogMessage(Debug, "%s handler task %s done , result is %s\n",
            //               td.threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
        }
    }

private:
    ThreadPool(int num = default_threadnum)
        : _threadnum(num)
    {
        // 初始化锁和条件变量
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        // 创建线程
        for (int i = 0; i < _threadnum; i++)
        {
            string threadname = "thread-" + to_string(i + 1);
            ThreadDate td(threadname);
            // 由于Thread执行的是线程池的类内函数，而Thread调用的函数中并没有this指针
            // 所以这里就使用bind函数，调整一下Thread调用函数的参数，使函数可以多接收一个参数
            _threads.push_back(Thread<ThreadDate>(threadname, bind(&ThreadPool<T>::ThreadRun, this, placeholders::_1), td));
            lg.LogMessage(Info, "%s is create\n", threadname.c_str());
        }
    }

    // 销毁锁和条件变量
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    ThreadPool(const ThreadPool&) = delete;
    const ThreadPool& operator=(const ThreadPool&) = delete;

private:
    queue<T> _q;
    vector<Thread<ThreadDate>> _threads;
    int _threadnum;
    static ThreadPool<T> *_psl;
    static pthread_mutex_t _sig_lock;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_psl = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::_sig_lock = PTHREAD_MUTEX_INITIALIZER;